VT-d: improve RMRR validity checking
authorKeir Fraser <keir.fraser@citrix.com>
Thu, 21 Jan 2010 09:12:01 +0000 (09:12 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Thu, 21 Jan 2010 09:12:01 +0000 (09:12 +0000)
Currently, Xen checks RMRR range and disables VT-d if RMRR range is
set incorrectly in BIOS rigorously. But, actually we can ignore the
RMRR if the device under its scope are not pci discoverable, because
the RMRR won't be used by non-existed or disabled devices.

This patch ignores the RMRR if the device under its scope are not pci
discoverable, and only checks the validity of RMRRs that are actually
used. In order to avoid duplicate pci device detection code, this
patch defines a function pci_device_detect for it.

Signed-off-by: Weidong Han <weidong.han@intel.com>
xen/drivers/passthrough/pci.c
xen/drivers/passthrough/vtd/dmar.c
xen/include/xen/pci.h

index 75de82a90dc3453ab47a28edeada749799e40b7f..bc6974c12281dd2a8563cc07b21d43c1803fe4b9 100644 (file)
@@ -361,6 +361,21 @@ out:
     return ret;
 }
 
+/*
+ * detect pci device, return 0 if it exists, or return 0
+ */
+int pci_device_detect(u8 bus, u8 dev, u8 func)
+{
+    u32 vendor;
+
+    vendor = pci_conf_read32(bus, dev, func, PCI_VENDOR_ID);
+    /* some broken boards return 0 or ~0 if a slot is empty: */
+    if ( (vendor == 0xffffffff) || (vendor == 0x00000000) ||
+         (vendor == 0x0000ffff) || (vendor == 0xffff0000) )
+        return 0;
+    return 1;
+}
+
 /*
  * scan pci devices to add all existed PCI devices to alldevs_list,
  * and setup pci hierarchy in array bus2bridge. This function is only
@@ -372,7 +387,6 @@ int __init scan_pci_devices(void)
     int bus, dev, func;
     u8 sec_bus, sub_bus;
     int type;
-    u32 l;
 
     spin_lock(&pcidevs_lock);
     for ( bus = 0; bus < 256; bus++ )
@@ -381,10 +395,7 @@ int __init scan_pci_devices(void)
         {
             for ( func = 0; func < 8; func++ )
             {
-                l = pci_conf_read32(bus, dev, func, PCI_VENDOR_ID);
-                /* some broken boards return 0 or ~0 if a slot is empty: */
-                if ( (l == 0xffffffff) || (l == 0x00000000) ||
-                     (l == 0x0000ffff) || (l == 0xffff0000) )
+                if ( pci_device_detect(bus, dev, func) == 0 )
                     continue;
 
                 pdev = alloc_pdev(bus, PCI_DEVFN(dev, func));
index 3ead126b79b3eda2d8a19b81f65e8cf81c4467b7..971100fe3e0ed2b137083e09001475b381d53d3d 100644 (file)
@@ -410,14 +410,6 @@ acpi_parse_one_rmrr(struct acpi_dmar_entry_header *header)
     u64 base_addr = rmrr->base_address, end_addr = rmrr->end_address;
     int ret = 0;
 
-    if ( base_addr >= end_addr )
-    {
-        dprintk(XENLOG_ERR VTDPREFIX,
-                "RMRR error: base_addr %"PRIx64" end_address %"PRIx64"\n",
-                base_addr, end_addr);
-        return -EFAULT;
-    }
-
 #ifdef CONFIG_X86
     /* This check is here simply to detect when RMRR values are
      * not properly represented in the system memory map and
@@ -441,9 +433,6 @@ acpi_parse_one_rmrr(struct acpi_dmar_entry_header *header)
 
     rmrru->base_address = base_addr;
     rmrru->end_address = end_addr;
-    dprintk(XENLOG_INFO VTDPREFIX,
-            "  RMRR region: base_addr %"PRIx64" end_address %"PRIx64"\n",
-            rmrru->base_address, rmrru->end_address);
 
     dev_scope_start = (void *)(rmrr + 1);
     dev_scope_end   = ((void *)rmrr) + header->length;
@@ -453,7 +442,50 @@ acpi_parse_one_rmrr(struct acpi_dmar_entry_header *header)
     if ( ret || (rmrru->scope.devices_cnt == 0) )
         xfree(rmrru);
     else
-        acpi_register_rmrr_unit(rmrru);
+    {
+        u8 b, d, f;
+        int i, ignore = 0;
+
+        for ( i = 0; i < rmrru->scope.devices_cnt; i++ )
+        {
+            b = PCI_BUS(rmrru->scope.devices[i]);
+            d = PCI_SLOT(rmrru->scope.devices[i]);
+            f = PCI_FUNC(rmrru->scope.devices[i]);
+
+            if ( pci_device_detect(b, d, f) == 0 )
+                ignore = 1;
+            else
+            {
+                ignore = 0;
+                break;
+            }
+        }
+
+        if ( ignore )
+        {
+            dprintk(XENLOG_WARNING VTDPREFIX,
+                "  Ignore the RMRR (%"PRIx64", %"PRIx64") due to "
+                "devices under its scope are not PCI discoverable!\n",
+                rmrru->base_address, rmrru->end_address);
+            xfree(rmrru);
+        }
+        else if ( base_addr > end_addr )
+        {
+            dprintk(XENLOG_WARNING VTDPREFIX,
+                "  The RMRR (%"PRIx64", %"PRIx64") is incorrect!\n",
+                rmrru->base_address, rmrru->end_address);
+            xfree(rmrru);
+            ret = -EFAULT;
+        }
+        else
+        {
+            dprintk(XENLOG_INFO VTDPREFIX,
+                "  RMRR region: base_addr %"PRIx64" end_address %"PRIx64"\n",
+                rmrru->base_address, rmrru->end_address);
+            acpi_register_rmrr_unit(rmrru);
+        }
+    }
+
     return ret;
 }
 
index 1740698cc6471269dec1add757ca810992e32a18..2f2014fd64e0b1fa050b87788444c27d6ab9c5f4 100644 (file)
@@ -74,6 +74,7 @@ enum {
     DEV_TYPE_PCI,
 };
 
+int pci_device_detect(u8 bus, u8 dev, u8 func);
 int scan_pci_devices(void);
 int pdev_type(u8 bus, u8 devfn);
 int find_upstream_bridge(u8 *bus, u8 *devfn, u8 *secbus);